﻿using K9Nano.FileStorage;
using MiniExcelLibs;

namespace K9Nano.Xlsx;

public abstract class XlsxHandlerBase<TImport, TExport>(IFileStorage storage) : IXlsxHandler
    where TImport : class, IXlsxImportTemplate, new()
    where TExport : class, new()
{
    /// <summary>
    /// 导出数据到文件
    /// </summary>
    /// <param name="records">带导出的数据</param>
    /// <param name="sheetName">工作表名。默认为Sheet1</param>
    /// <returns>导出文件路径</returns>
    protected virtual async Task<string> ExportAsync(object records, string? sheetName = null, CancellationToken cancellation = default)
    {
        var fullPath = GetTmpFile();

        await MiniExcel.SaveAsAsync(fullPath, records, sheetName: sheetName ?? "Sheet1", cancellationToken: cancellation);

        return fullPath;
    }

    /// <summary>
    /// 导出数据到文件
    /// </summary>
    /// <returns>导出文件路径</returns>
    public async Task<string> ExportAsync(object records, CancellationToken cancellation = default)
    {
        return await ExportAsync(records, "导出数据", cancellation); ;
    }

    public async Task<ImportResult> ImportAsync(Stream xlsxFile)
    {
        var records = await MiniExcel.QueryAsync<TImport>(xlsxFile);
        if (records is not List<TImport> imports)
        {
            imports = records.ToList();
        }

        if (imports.Count == 0)
        {
            return new ImportResult(true, 0, null);
        }

        var validateFailed = false;
        foreach (var row in imports)
        {
            row.Error = await OnValidatingAsync(row);
            if (!validateFailed && !string.IsNullOrEmpty(row.Error))
            {
                validateFailed = true;
            }
        }

        if (validateFailed)
        {
            var failedFile = await ExportAsync(imports, "校验数据");
            return new ImportResult(false, 0, failedFile);
        }

        var failedRows = await OnImportingAsync(imports);
        var successRows = imports.Count - failedRows.Count;
        string? failedResultFile = null;
        if (failedRows.Count > 0)
        {
            failedResultFile = await ExportAsync(failedRows, "失败数据");
        }
        return new ImportResult(successRows > 0, successRows, failedResultFile);
    }

    public async Task<string> ExportTemplateAsync(CancellationToken cancellation = default)
    {
        return await ExportAsync(Array.Empty<TImport>(), "模板", cancellation);
    }

    protected virtual string GetTmpFile() => storage.GetTmpFile(".xlsx");

    /// <summary>
    /// 校验待导入的数据
    /// </summary>
    /// <returns>校验成功时返回null，否则返回错误信息</returns>
    protected abstract Task<string?> OnValidatingAsync(TImport record);

    /// <summary>
    /// 将数据导入数据库
    /// </summary>
    /// <returns>导入失败的数据</returns>
    protected abstract Task<IReadOnlyList<TImport>> OnImportingAsync(IEnumerable<TImport> records);
}